#include <assert.h>
#include <stdlib.h>
#include <wlr/interfaces/wlr_keyboard.h>
#include "backend/sylixosinput.h"
#include "keymap.h"

struct wlr_sylixosinput_input_device *device_from_keyboard(
		struct wlr_keyboard *kb) {
	assert(kb->impl == &sylixosinput_keyboard_impl);

	struct wlr_sylixosinput_input_device *dev = wl_container_of(kb, dev, keyboard);
	return dev;
}

static void keyboard_set_leds(struct wlr_keyboard *wlr_kb, uint32_t leds) {
	// FIXME: do noyhing in sylixos?
}

const struct wlr_keyboard_impl sylixosinput_keyboard_impl = {
	.name = "sylixosinput-keyboard",
	.led_update = keyboard_set_leds
};

void init_device_keyboard(struct wlr_sylixosinput_input_device *dev) {
	struct wlr_keyboard *wlr_kb = &dev->keyboard;
	wlr_keyboard_init(wlr_kb, &sylixosinput_keyboard_impl, "xkbd");
	wlr_kb->base.vendor = 0xdead;
	wlr_kb->base.product = 0xdead;
}

void handle_keyboard_key(keyboard_event_notify *event, struct wlr_keyboard *kb) {
	struct wlr_keyboard_key_event wlr_event = { 0 };
	struct timeval time_us;
    int unicode = event->keymsg[0];

    // covert keycode from sylixos to linux evdev
    // xkbcommon use linux evdev keycode as input default
    if ((unicode < 0xff) && (unicode > 0)) {
        unicode = asciikeytbl[unicode];
    } else {
        switch (unicode) {
        case K_F1:     unicode = KEY_F1;     break;
        case K_F2:     unicode = KEY_F2;     break;
        case K_F3:     unicode = KEY_F3;     break;
        case K_F4:     unicode = KEY_F4;     break;
        case K_F5:     unicode = KEY_F5;     break;
        case K_F6:     unicode = KEY_F6;     break;
        case K_F7:     unicode = KEY_F7;     break;
        case K_F8:     unicode = KEY_F8;     break;
        case K_F9:     unicode = KEY_F9;     break;
        case K_F10:    unicode = KEY_F10;    break;
        case K_F11:    unicode = KEY_F11;    break;
        case K_F12:    unicode = KEY_F12;    break;
        case K_F13:    unicode = KEY_F13;    break;
        case K_F14:    unicode = KEY_F14;    break;
        case K_F15:    unicode = KEY_F15;    break;
        case K_F16:    unicode = KEY_F16;    break;
        case K_F17:    unicode = KEY_F17;    break;
        case K_F18:    unicode = KEY_F18;    break;
        case K_F19:    unicode = KEY_F19;    break;
        case K_F20:    unicode = KEY_F20;    break;

        case K_CAPSLOCK:     unicode = KEY_CAPSLOCK;     break;
        case K_NUMLOCK:      unicode = KEY_NUMLOCK;      break;

        case K_PRINTSCREEN:  unicode = KEY_SYSRQ;        break;
        case K_SCROLLLOCK:   unicode = KEY_SCROLLLOCK;   break;
        case K_PAUSEBREAK:   unicode = KEY_PAUSE;        break;

        case K_CTRL:         unicode = KEY_LEFTCTRL;     break;
        case K_ALT:          unicode = KEY_LEFTALT;      break;
        case K_SHIFT:        unicode = KEY_LEFTSHIFT;    break;
        case K_CTRLR:        unicode = KEY_RIGHTCTRL;    break;
        case K_ALTR:         unicode = KEY_RIGHTALT;     break;
        case K_SHIFTR:       unicode = KEY_RIGHTSHIFT;   break;

        case K_INSERT:       unicode = KEY_INSERT;      break;
        case K_HOME:         unicode = KEY_HOME;        break;
        case K_DELETE:       unicode = KEY_DELETE;      break;
        case K_END:          unicode = KEY_END;         break;
        case K_PAGEUP:       unicode = KEY_PAGEUP;      break;
        case K_PAGEDOWN:     unicode = KEY_PAGEDOWN;    break;

        case K_UP:           unicode = KEY_UP;          break;
        case K_DOWN:         unicode = KEY_DOWN;        break;
        case K_LEFT:         unicode = KEY_LEFT;        break;
        case K_RIGHT:        unicode = KEY_RIGHT;       break;
        default:             unicode = 0;               break;
        }
    }

	gettimeofday(&time_us, NULL);
	wlr_event.time_msec = usec_to_msec(time_us.tv_sec * 1000 * 1000 + time_us.tv_usec);
	wlr_event.keycode = unicode;

    if (event->type & KE_PRESS) {
        wlr_event.state = WL_KEYBOARD_KEY_STATE_PRESSED;
    } else if (event->type & KE_RELEASE) {
        wlr_event.state = WL_KEYBOARD_KEY_STATE_RELEASED;
    }

	wlr_event.update_state = true;
	wlr_keyboard_notify_key(kb, &wlr_event);
}
